/**
 * 
 */
package gui.controller;

import engine.ExternalSource;
import engine.Service;
import gui.view.EngineMain;
import gui.view.InputPanel;
import gui.view.source.SourceLeftPanel;
import gui.view.source.SourceRightPanel;
import gui.view.source.SourcesPanel;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.JOptionPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;

import massDistribution.MeasuredAttribute;
import stubs.AttributeValueGenerator;
import stubs.ServiceStub;

/**
 * This Listener observes the EDIT Action of the left panel, and the Ok action
 * of the right panel.
 * 
 * @author Elisa Costante
 * 
 */
public class SourceMainListener implements ActionListener,
		ListSelectionListener {

	private SourcesPanel mainPanel;
	private SourceRightListener rightListener;
	private ExternalSource selectedSource;
	private SourceLeftPanel leftPanel;
	private SourceRightPanel rightPanel;
	private EngineMain frame;
	private ArrayList<ExternalSource> clonedSOurces;

	/**
	 * @param sourcesPanel
	 * @param leftListener
	 * @param rightListener
	 */
	public SourceMainListener(SourcesPanel sourcesPanel,
			SourceRightListener rightListener) {
		this.mainPanel = sourcesPanel;
		this.leftPanel = mainPanel.getLeftPanel();
		this.rightPanel = mainPanel.getRightPanel();
		this.rightListener = rightListener;
		this.frame = mainPanel.getFrame();
	}

	@Override
	public void actionPerformed(ActionEvent e) {

		if (e.getActionCommand().equalsIgnoreCase("editSource")) {
			editSourceAction();

		} else if (e.getActionCommand().equalsIgnoreCase("ok")) {
			try {
				okAction();
			} catch (CloneNotSupportedException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}

		} else if (e.getActionCommand().equalsIgnoreCase("showDataButton")) {

			// show the internal frame with the generated data
			InputPanel inputPanel = new InputPanel(frame.getSourceList(), frame
					.getAttributeArrayList(), this);

			mainPanel.openInternalFrame(inputPanel);

		} else if (e.getActionCommand().equalsIgnoreCase("generate")) {
			clonedSOurces = getCLonedSources(frame.getSourceList());
			AttributeValueGenerator.generateAction(clonedSOurces);
			// Update the source list
			mainPanel.getInputPanel().refreshDataModel(clonedSOurces);

		} else if (e.getActionCommand().equalsIgnoreCase("okInputPanel")) {
			// update the sourcelist
			if (clonedSOurces != null)
				frame.setSourceList(clonedSOurces);
			// Close the internal frame
			mainPanel.closeInternalFrame();
		}

	}

	private ArrayList<ExternalSource> getCLonedSources(
			ArrayList<ExternalSource> allSources) {
		if (allSources != null) {
			ArrayList<ExternalSource> clonedSources = new ArrayList<ExternalSource>();

			for (ExternalSource externalSource : allSources) {

				ExternalSource clonedSOurce = new ExternalSource(externalSource
						.getIdentifierName());

				if (externalSource.getMeasuredServices() != null) {
					for (Service service : externalSource.getMeasuredServices()) {
						try {
							clonedSOurce.addMeasuredService((Service) service
									.clone());
						} catch (CloneNotSupportedException e) {
							e.printStackTrace();
						}

					}
				}
				clonedSources.add(clonedSOurce);
			}
			return clonedSources;
		}
		return null;
	}

	/*
	 * Just Change the selectedSource and the services monitored from that
	 * source
	 */
	@Override
	public void valueChanged(ListSelectionEvent e) {

		if (e.getValueIsAdjusting())
			;// Ignore extra messages
		else {
			// Row selected change
			ListSelectionModel lsm = (ListSelectionModel) e.getSource();

			int selectedRow = getSelectedRow(lsm);

			if (selectedRow >= 0) {
				// The Selected row is changed
				selectedSource = getSelectedSource();
				if (selectedSource != null
						&& selectedSource.getMeasuredServices() != null) {
					// // show the monitored services
					rightPanel.setServicesTableModelList(selectedSource
							.getMeasuredServices(), true);

				} else if (selectedSource != null
						&& selectedSource.getMeasuredServices() == null) {
					rightPanel.setServicesTableModelList(frame
							.getMonitoredServices(), false);
				}
				rightPanel.setAttributeTableModelList(
						new ArrayList<MeasuredAttribute>(), false);
			}
		}

	}

	private void editSourceAction() {
		// Get the selected source
		selectedSource = getSelectedSource();

		if (selectedSource != null) {

			EngineMain.setEnabledtPanel(rightPanel, true);
			EngineMain.setEnabledtPanel(rightPanel
					.getAttributeForServicePanel(), false);

			rightPanel.getSelectedSourceLabel().setText(
					selectedSource.getIdentifierName());

			EngineMain.setEnabledtPanel(leftPanel, false);
			rightListener.setSelectedSource(selectedSource);
		} else {
			JOptionPane.showMessageDialog(mainPanel,
					"You must select a source to edit.");
		}

	}

	/**
	 * Return the selected source or null if no row is selected.
	 * 
	 * @return the selected source or null if no source is selected.
	 */
	public ExternalSource getSelectedSource() {
		int selectedRow = leftPanel.getSourcesTable().getSelectedRow();
		if (selectedRow >= 0) {
			String selectedSourceName = (String) leftPanel
					.getSourcesTableModel().getValueAt(selectedRow, 0);
			ExternalSource selectedSource = frame
					.getSourceFromName(selectedSourceName);
			if (selectedSource != null)
				return selectedSource;

		}
		return null;
	}

	/**
	 * @param selectedSource
	 *            the selectedSource to set
	 */
	public void setSelectedSource(ExternalSource selectedSource) {
		this.selectedSource = selectedSource;
	}

	/**
	 * Set the supervisioned services for the selectedSource
	 * 
	 * @throws CloneNotSupportedException
	 */
	private void okAction() throws CloneNotSupportedException {
		selectedSource = rightListener.getSelectedSource();
		// The selected source has to be set up again
		// selectedSource.setMeasuredServices(null);

		// This list contains all the services and, for each service, all the
		// monitored attributes.

		DefaultTableModel servicesTableModel = rightPanel
				.getServicesTableModel();

		for (int i = 0; i < servicesTableModel.getRowCount(); i++) {

			String serviceName = (String) servicesTableModel.getValueAt(i, 0);
			Boolean selected = (Boolean) servicesTableModel.getValueAt(i, 1);
			String trustLevel = (String) servicesTableModel.getValueAt(i, 2);
			ServiceStub service = (ServiceStub) selectedSource
					.getMeasuredService(serviceName);
			if (service != null) {
				if (selected) {
					service.setTrustValueFromString(trustLevel);
				} else {
					selectedSource.getMeasuredServices().remove(service);
				}
			}
		}
		if (selectedSource.getMeasuredServices() != null
				&& selectedSource.getMeasuredServices().size() >= 0)

			rightPanel.setServicesTableModelList(selectedSource
					.getMeasuredServices(), true);
		else
			rightPanel.setServicesTableModelList(frame.getMonitoredServices(),
					false);

		updateSourceList();
		EngineMain.setEnabledtPanel(rightPanel, false);

		EngineMain.setEnabledtPanel(leftPanel, true);
	}

	/**
	 * Return the selectedRow or -1 if no row is selected.
	 * 
	 * @param lsm
	 * @return
	 */
	private int getSelectedRow(ListSelectionModel lsm) {
		int selectedRow = -1;
		if (!lsm.isSelectionEmpty()) {
			// Find out which indexes are selected.
			selectedRow = lsm.getMinSelectionIndex();

		}
		return selectedRow;
	}

	/**
	 * retrieve the source from the list into the frame and set it.
	 */
	private void updateSourceList() {
		ArrayList<ExternalSource> allSource = frame.getSourceList();
		for (ExternalSource source : allSource) {
			if (source.equals(selectedSource)) {
				source = selectedSource;
			}
		}
	}

}
